using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;

using PHSRAG.Insight21.BusinessObjects;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using PHSRAG.Utility;

namespace PHSRAG.Insight21.ClinicalTrials
{
   /// <summary>
   /// The BudgetProcedures class represents a collection of BudgetProcedure objects.  It is 
   /// responsible for loading and saving the Budget Procedures
   /// </summary>
   public class BudgetProcedures : SaveableBusinessObject, IEnumerable
   {
      #region Constants
      private const string BudgetProceduresKey = "BudgetProcedures_0A7C68A2-2BFA-4e01-9207-141743F8225A";
      private const string TableName = "BudgetProcedures";
      #endregion

      #region Instance Variables
      private ArrayList budgetProcedures = new ArrayList( );
      private Budget budget;
      private SqlCommand updateBudgetProceduresCommand;
      private SqlCommand deleteBudgetProceduresCommand;
      #endregion

      #region Constructor
      /// <summary>
      /// Initialize the base class with the specified cache policy and create the data container.
      /// </summary>
      public BudgetProcedures( ICachePolicy cachePolicy ) : base ( cachePolicy )
      {
         DataContainer = new DataSet( );
         budget = (Budget)CachePolicy.GetCachedObject( Budget.CacheKey );
      }
      #endregion
   
      #region Base Methods
      /// <summary>
      /// Cache this instance using the prevalent cache policy.
      /// </summary>
      public override void Cache( )
      {
         CachePolicy.Cache( BudgetProceduresKey, this );
      }

      /// <summary>
      /// Remove this instance from the cache using the prevalent cache policy.
      /// </summary>
      public override void UnCache( )
      {
         CachePolicy.UnCache( BudgetProceduresKey );
      }

      /// <summary>
      /// Load procedure details pertaining to a specific budget.
      /// </summary>
      /// <param name="connectionString">Connection string to the database</param>
      /// <param name="args">Object array which must contain the budget ID</param>
      public override void Load( string connectionString, params object[] args )
      {
         if ( args.Length != 1 )
            throw new Exception("BudgetProcedures load requires a budget id.");
			
         DataAccess.LoadDataSet( DataContainer, TableName, connectionString, "GetClinicalTrialBudgetProcedures", 
            Utility.DataAccess.BuildSqlParameterArray( "@budgetId", SqlDbType.Int, args[0] ) );

         if ( DataContainer.Tables.Count == 0 )
            throw new Exception("Failed to load Budget Procedures information.");

         foreach( DataRow budgetProcedureRow in DataContainer.Tables[TableName].Rows )
         {
            budgetProcedures.Add( new BudgetProcedure( CachePolicy, budgetProcedureRow  ) );
         }
      }

      /// <summary>
      /// Saves procedure details associated with this budget.  
      /// </summary>
      /// <param name="connectionString">Connection string to the database</param>
      /// <param name="args">Optional parameters (ignored)</param>
      public override void Save( string connectionString, params object[] args )
      {
         SqlConnection connection = new SqlConnection( connectionString );
         SqlTransaction transaction = null;
         try
         {
            connection.Open( );
            transaction = connection.BeginTransaction( );
            BuildCommands( );
            updateBudgetProceduresCommand.Connection = connection;
            updateBudgetProceduresCommand.Transaction = transaction;
            deleteBudgetProceduresCommand.Connection = connection;
            deleteBudgetProceduresCommand.Transaction = transaction;

            SqlDataAdapter adapter = new SqlDataAdapter( );
            adapter.InsertCommand = updateBudgetProceduresCommand;
            adapter.UpdateCommand = updateBudgetProceduresCommand;
            adapter.DeleteCommand = deleteBudgetProceduresCommand;
            adapter.Update( DataContainer, TableName );

            foreach ( BudgetProcedure budgetProcedure in budgetProcedures )
            {
                if (budgetProcedure.Id != 0)
                {
                    foreach (BudgetMilestoneVisit budgetMilestoneVisit in budgetProcedure.BudgetMilestoneVisits)
                    {
                        budgetMilestoneVisit.RelateId = budgetProcedure.Id;
                    }
                    budgetProcedure.BudgetMilestoneVisits.Save(connectionString);
                }
            }
            transaction.Commit( );
         }
         catch( Exception e )
         {
            transaction.Rollback( );
            throw(new Exception(@"Error saving Budget Milestone Visits to the database.", e));
         }
         finally
         {
            if ( connection.State != ConnectionState.Closed )
               connection.Close( );
            transaction.Dispose( );
         }
      }
      #endregion

      #region Private Methods
      private void BuildCommands( )
      {
         if ( updateBudgetProceduresCommand == null )
         {
            updateBudgetProceduresCommand = new SqlCommand( );
            updateBudgetProceduresCommand.CommandText = "UpdateClinicalTrialBudgetProcedures";
            updateBudgetProceduresCommand.CommandType = CommandType.StoredProcedure;
			updateBudgetProceduresCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			SqlParameter paramId = new SqlParameter( "@budgetProcedureId", SqlDbType.Int );
            paramId.SourceColumn = "Id";
            paramId.Direction = ParameterDirection.InputOutput;
            updateBudgetProceduresCommand.Parameters.Add( paramId );
            updateBudgetProceduresCommand.Parameters.Add( "@budgetId", SqlDbType.Int ).SourceColumn = "ClinicalTrialBudgetId";
            updateBudgetProceduresCommand.Parameters.Add( "@procedureChargeCode", SqlDbType.Int ).SourceColumn = "ProcedureChargeCode";
            updateBudgetProceduresCommand.Parameters.Add( "@applyOverhead", SqlDbType.Bit ).SourceColumn = "ApplyOverhead";
            updateBudgetProceduresCommand.Parameters.Add( "@inpatient", SqlDbType.Bit ).SourceColumn = "Inpatient";
            updateBudgetProceduresCommand.Parameters.Add( "@professionalFee", SqlDbType.Decimal ).SourceColumn = "ProfessionalFee";
            updateBudgetProceduresCommand.Parameters.Add( "@procedureCost", SqlDbType.Decimal).SourceColumn = "ProcedureCost";
            updateBudgetProceduresCommand.Parameters.Add( "@IsFacility", SqlDbType.Bit).SourceColumn = "IsFacility";
            updateBudgetProceduresCommand.Parameters.Add( "@useHospitalPricing", SqlDbType.Bit).SourceColumn = "UseHospitalPricing";

         }

         if ( deleteBudgetProceduresCommand == null )
         {
            deleteBudgetProceduresCommand = new SqlCommand( );
            deleteBudgetProceduresCommand.CommandText = "DeleteClinicalTrialBudgetProcedures";
            deleteBudgetProceduresCommand.CommandType = CommandType.StoredProcedure;
			deleteBudgetProceduresCommand.CommandTimeout = Convert.ToInt32(Utility.Settings.GetKeyValue("Database.Insight.CommandTimeout", "0"));
			SqlParameter paramDeleteId = new SqlParameter( "@budgetProcedureId", SqlDbType.Int );
            paramDeleteId.SourceColumn = "Id";
            paramDeleteId.Direction = ParameterDirection.Input;
            deleteBudgetProceduresCommand.Parameters.Add( paramDeleteId );
         }
      }
      #endregion

      #region IEnumerable Methods
      /// <summary>
      /// Gets an IEnumerator interface.  Required for implementation of IEnumerable
      /// </summary>
      /// <returns>IEnumerator</returns>
      public IEnumerator GetEnumerator( )
      {
		   return budgetProcedures.GetEnumerator( );
      }
      #endregion

      #region Public Collection helpers
      /// <summary>
      /// The Count property returns the number of items in the Budget Expenses collection
      /// </summary>
      public int Count
      {
         get
         {
            return budgetProcedures.Count;
         }
      }

      /// <summary>
      /// Indexer to get a specific Budget Procedure from the collection
      /// </summary>
      public BudgetProcedure this[int index]
      {
         get
         {
            return (BudgetProcedure)budgetProcedures[ index ];
         }
      }
      #endregion

      #region Public Methods
      /// <summary>
      /// Creates a new BudgetProcedure and adds the item to the collection.  Also sets default
      /// properties on the BudgetProcedure.
      /// </summary>
      /// <returns>BudgetProcedure</returns>
      public BudgetProcedure CreateNewBudgetProcedure( )
      {
         DataRow newRow = DataContainer.Tables[TableName].NewRow( );
         DataContainer.Tables[TableName].Rows.Add( newRow );
         BudgetProcedure newBudgetProcedure = new BudgetProcedure( CachePolicy, newRow );
         newBudgetProcedure.BudgetId = budget.Id;

         newBudgetProcedure.ApplyOverhead = true;
         newBudgetProcedure.ProfessionalFee = "0.00";
         newBudgetProcedure.IsFacility = true;
         newBudgetProcedure.UseHospitalPricing = true;
         // Setup the budgetmilestonevisits
         BudgetVisits budgetVisits = budget.BudgetVisits;
         foreach ( BudgetVisit budgetVisit in budgetVisits )
         {
            newBudgetProcedure.BudgetMilestoneVisits.CreateNewBudgetMilestoneVisit( budgetVisit.Id, "BudgetProcedure" );
         }
         budgetProcedures.Add( newBudgetProcedure );
		   return newBudgetProcedure;
      }

      /// <summary>
      /// Removes a specific BudgetProcedure from the collection.  Must call save on BudgetProcedures
      /// to save this change to the database.
      /// </summary>
      /// <param name="budgetProcedure">BudgetProcedure to remove from the collection.</param>
      public void RemoveBudgetProcedure( BudgetProcedure budgetProcedure )
      {
		  if(budgetProcedure.Id == 0) 
		  {
			  DataContainer.Tables[TableName].Rows.RemoveAt(  DataContainer.Tables[TableName].Rows.Count - 1 );
		  }
		  else
		  {
			  DataContainer.Tables[TableName].Select( string.Format( "Id = {0}", budgetProcedure.Id ) )[0].Delete( );
		  }
		  budgetProcedures.Remove( budgetProcedure );

      }
      /// <summary>
      /// Removes a specific BudgetProcedure from the collection.  Must call save on BudgetProcedures
      /// to save this change to the database.
      /// </summary>
      /// <param name="budgetProcedure">BudgetProcedure to remove from the collection.</param>
       public void RemoveBudgetProcedure(BudgetProcedure budgetProcedure, int rowNumber)
      {

          DataContainer.Tables[TableName].Rows.RemoveAt(rowNumber);

          budgetProcedures.Remove(budgetProcedure);

      }
      #endregion	     
   }
}